package com.stone.inventory.core.config;

import com.stone.inventory.sharding.config.properties.DbShardingProperty;
import com.stone.inventory.sharding.config.resolver.ShardingResolver;
import com.stone.inventory.sharding.helper.ShardingHelper;
import com.stone.inventory.sharding.id.intercepter.MybatisShardingIdInterceptor;
import com.stone.inventory.sharding.infra.constant.ShardingConstants;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import io.shardingsphere.api.config.rule.ShardingRuleConfiguration;
import io.shardingsphere.shardingjdbc.api.ShardingDataSourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

/**
 * 分片数据源自动配置
 *
 * @author Mr_wenpan@163.com 2021/08/16 23:08
 */
@Configuration
@ConditionalOnProperty(prefix = "stone.inv.db", name = {"sharding"}, havingValue = "true")
public class StoneShardingDataSourceAutoConfiguration {

    /**
     * 注入数据源配置信息
     */
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariConfig hikariConfig(DataSourceProperties dataSourceProperties) {
        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(dataSourceProperties.getUrl());
        hikariConfig.setUsername(dataSourceProperties.getUsername());
        hikariConfig.setPassword(dataSourceProperties.getPassword());
        return hikariConfig;
    }

    /**
     * 注入数据源
     */
    @Bean
    public DataSource dataSource(HikariConfig hikariConfig,
                                 ShardingHelper shardingHelper,
                                 DbShardingProperty dbShardingProperty) throws SQLException {
        // 构造数据源
        HikariDataSource hikariDataSource = new HikariDataSource(hikariConfig);
        Map<String, DataSource> dataSourceMap = new HashMap<>(10);
        dataSourceMap.put(ShardingConstants.DataSource.MAIN, hikariDataSource);

        //分片规则配置
        ShardingRuleConfiguration shardingRuleConfiguration =
                ShardingResolver.parseShardingRuleConfiguration(dbShardingProperty, shardingHelper);

        return ShardingDataSourceFactory.createDataSource(dataSourceMap,
                shardingRuleConfiguration, dbShardingProperty.getConfig(), dbShardingProperty.getProps());
    }

    /**
     * MySQL分片拦截器
     */
    @Bean
    public MybatisShardingIdInterceptor mybatisShardingIdInterceptor(ShardingHelper shardingHelper) {
        return new MybatisShardingIdInterceptor(shardingHelper);
    }
}
